package com.base.vistter.iframe.aspectj;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.base.vistter.iframe.annotation.Log;
import com.base.vistter.iframe.bean.Result;
import com.base.vistter.iframe.bean.SystemContextHolder;
import com.base.vistter.iframe.entity.SysLog;
import com.base.vistter.iframe.model.LoginUserModel;
import com.base.vistter.iframe.service.SysLogService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.RequestFacade;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class LogAspect {

    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Current Time");

    @Resource(name = "sysLogService")
    private SysLogService sysLogService;

    @Before(value = "@annotation(autoLog)")
    public void onBefore(JoinPoint joinPoint, Log autoLog) {
        TIME_THREADLOCAL.set(System.currentTimeMillis());
    }

    @AfterReturning(pointcut = "@annotation(autoLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log autoLog, Object jsonResult) {
        handleLog(joinPoint, autoLog, null, jsonResult);
    }

    @AfterThrowing(value = "@annotation(autoLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log autoLog, Exception e) {
        handleLog(joinPoint, autoLog, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, Log autoLog, final Exception e, Object jsonResult) {
        try {
            SysLog sysLog = new SysLog();
            sysLog.setTitle(autoLog.title());
            sysLog.setBusinessType(autoLog.businessType().ordinal());
            sysLog.setOperatorType(autoLog.operatorType().ordinal());
            sysLog.setOperatorTime(new Date());
            sysLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
            LoginUserModel loginUserModel = SystemContextHolder.getSessionContext();
            if (loginUserModel != null) {
                sysLog.setOperatorId(loginUserModel.getUserId());
                sysLog.setOperatorName(loginUserModel.getUsername());
            }
            setMethod(joinPoint, sysLog);
            setOperatorRequest(joinPoint, sysLog);
            //获取结果
            if (jsonResult != null) {
                Result result = (Result) jsonResult;
                if (result.getCode() == 200) {
                    sysLog.setStatus(0);
                    sysLog.setJsonResult(JSON.toJSONString(result));
                } else {
                    sysLog.setStatus(1);
                    sysLog.setJsonResult(result.getMessage());
                }
            } else {
                sysLog.setStatus(1);
                sysLog.setJsonResult(e.getMessage());
            }
            sysLogService.save(sysLog);
        } catch (Exception exception) {
            log.error(exception.getMessage());
        } finally {
            TIME_THREADLOCAL.remove();
        }
    }

    private void setMethod(JoinPoint joinPoint, SysLog sysLog) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        sysLog.setMethod(className + "." + methodName + "()");
    }

    private void setOperatorRequest(JoinPoint joinPoint, SysLog sysLog) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        sysLog.setRequestUrl(request.getRequestURI());
        sysLog.setRequestMethod(request.getMethod());

        Map<String, String[]> map = request.getParameterMap();
        if (!map.isEmpty()) {
            sysLog.setOperatorParams(JSONObject.toJSONString(map));
        } else {
            Object[] args = joinPoint.getArgs();
            if (args != null) {
                sysLog.setOperatorParams(argsArrayToString(args));
            }
        }
    }

    private String argsArrayToString(Object[] paramsArray) {
        StringBuilder params = new StringBuilder();
        if (paramsArray != null) {
            for (Object object : paramsArray) {
                if (object != null && isFilterObject(object)) {
                    Object jsonObj = JSONObject.toJSONString(object);
                    params.append(jsonObj.toString()).append(" ");
                }
            }
        }
        return params.toString().trim();
    }

    public boolean isFilterObject(final Object o) {
        if (o instanceof RequestFacade) {
            return false;
        }
        return true;
    }
}